package bd;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import negocios.ColecaoUsuarios;
import negocios.Usuario;

import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import bd.excecoes.XMLException;

/**
 * Classe que manipula arquivos XML, criando, editando ou excluindo objetos do
 * tipo Usuario. Implementa o padrao Singleton.
 * 
 * @author Jonathan Brilhante
 * @author Jose Rafael
 * @author Nata Venancio
 * @author Renato Almeida
 * 
 * @version 2.0
 */

public class EditorXML {
	private static final String SEP = System.getProperty("file.separator");

	private static EditorXML instance;

	private String path = "db" + SEP + "usuarios.xml";
	private GeraElementosXML geraElementos;
	private GeraObjetos geraObjetos;
	private LerXML lerXML;
	private CriaXML criaXML;
	private Document doc;

	private EditorXML() {
		geraElementos = new GeraElementosXML(null);
		geraObjetos = new GeraObjetos(null);
		criaXML = new CriaXML("bancoUsuarios", path);
		lerXML = new LerXML(path);
	}

	/**
	 * Retorna a instancia unica do editor
	 * 
	 * @return a instancia unica do editor
	 */
	public static synchronized EditorXML getInstance() {
		if (instance == null) {
			instance = new EditorXML();
		}
		return instance;
	}

	/**
	 * 
	 * Seta o caminho do arquivo a ser criado.
	 * 
	 * @param caminho
	 */
	public void setPath(String caminho) {
		path = caminho;
	}

	/**
	 * Retorna todos os usuarios do banco de dados.
	 * 
	 * @return todos os usuarios do banco de dados.
	 * @throws DOMException
	 * @throws IOException
	 * @throws XMLException
	 */
	public ColecaoUsuarios getUsuarios() throws DOMException, IOException,
			XMLException {
		ColecaoUsuarios logins = new ColecaoUsuarios();
		File fileAux = new File(path);
		if (!fileAux.exists()) {
			salvaModificacoes(logins);
		}
		lerXML = new LerXML(path);
		Document doc = lerXML.getDoc();
		geraObjetos.setDoc(doc);
		Element raiz = doc.getDocumentElement();
		NodeList usuarios = raiz.getElementsByTagName("usuario");
		for (int i = 0; i < usuarios.getLength(); i++) {
			Element usuarioAuxiliar = (Element) usuarios.item(i);
			Usuario novoUsuario = geraObjetos
					.criarObjetoUsuario(usuarioAuxiliar);
			logins.add(novoUsuario);
		}
		return logins;
	}

	/**
	 * Adiciona um usuario ao banco de dados.
	 * 
	 * @param usuario
	 */
	private void adicionarUsuario(Usuario usuario) {
		Element raiz = doc.getDocumentElement();
		Element usuarioElemento = geraElementos.criarElementoUsuario(usuario);
		raiz.appendChild(usuarioElemento);
	}

	/**
	 * Atualiza o documento do xml.
	 * 
	 * @param doc
	 */
	private void setDoc(Document doc) {
		this.doc = doc;
		geraElementos.setDoc(doc);
	}

	/**
	 * Salva as modificacoes ocorridas no arquivo XML.
	 * 
	 * @param usuarios
	 *            a colecao de usuarios
	 */
	public void salvaModificacoes(ColecaoUsuarios usuarios) {
		Document doc = criaXML.getDoc();
		setDoc(doc);
		for (Usuario us : usuarios) {
			this.adicionarUsuario(us);
		}
		DOMSource source = new DOMSource(doc);
		StreamResult result = null;
		try {
			FileOutputStream fileStream = new FileOutputStream(path);
			result = new StreamResult(fileStream);
		} catch (FileNotFoundException erro) {
			throw new XMLException("Problema na criacao do arquivo");
		}
		TransformerFactory tf = TransformerFactory.newInstance();
		Transformer serializer = null;
		try {
			serializer = tf.newTransformer();
		} catch (TransformerConfigurationException erro) {
			throw new XMLException("Problema na serializacao do arquivo");
		}
		serializer.setOutputProperty(OutputKeys.INDENT, "yes");
		try {
			serializer.transform(source, result);
		} catch (TransformerException erro) {
			throw new XMLException("Problema na copia do arquivo");
		}
	}
}